using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System.Xml.Serialization;
using Tomahawk.Serialization;
using System.IO;
using Tomahawk.Serialization.SerialBoost;

namespace Tomahawk.Resources.LightningBolts
{
    public struct Range
    {
        public Range(float min, float max)
        {
            Min = min;
            Max = max;
        }
        public float Min;
        public float Max;
    }

    public enum LightningSubdivisionOp
    {
        /// <summary>
        /// Take a point on the line and modify its position
        /// </summary>
        Jitter,
        /// <summary>
        /// Take a point on the line, modify it's position, and 
        /// generate a new segment starting in this point
        /// </summary>
        JitterAndFork
    }

    public sealed class LightningDescriptor : IDisposable
    {
        private Range subdivisionFraction = new Range(0.45f, 0.55f);
        private Range jitterForwardDeviation= new Range(-1.0f, 1.0f);
        private Range jitterLeftDeviation = new Range(-1.0f, 1.0f);
        private float jitterDeviationRadius = 3.0f;
        private float jitterDecayRate = 0.6f;
        private float forkLengthPercentage = 0.5f;
        private float forkDecayRate = 0.5f;
        private Range forkForwardDeviation = new Range(0.0f, 1.0f);
        private Range forkLeftDeviation = new Range(-1.0f, 1.0f);
        private Color interiorColor = Color.White;
        private Color exteriorColor = Color.Blue;
        private float baseWidth = 0.6f;
        private bool isWidthDecreasing = true;
        private float animationFramerate = -1.0f;
        private SerializableList<LightningSubdivisionOp> topology = new SerializableList<LightningSubdivisionOp>();

        public static LightningDescriptor Default
        {
            get {
                LightningDescriptor ld = new LightningDescriptor();
                ld.topology.Add(LightningSubdivisionOp.JitterAndFork);
                ld.topology.Add(LightningSubdivisionOp.JitterAndFork);
                ld.topology.Add(LightningSubdivisionOp.Jitter);
                ld.topology.Add(LightningSubdivisionOp.Jitter);
                ld.topology.Add(LightningSubdivisionOp.JitterAndFork);
                return ld; }
        }

        public static LightningDescriptor ElectricityBolt
        {
            get {
                LightningDescriptor ld = new LightningDescriptor();
                ld.ForkDecayRate = 1.0f;
                ld.ForkLengthPercentage = 0.2f;
                ld.BaseWidth = 0.3f;
                ld.ExteriorColor = Color.Navy;
                ld.ForkForwardDeviation = new Range(-1, 1);
                ld.ForkLeftDeviation = new Range(-1, 1);
                ld.ForkLengthPercentage = 0.2f;
                ld.InteriorColor = Color.White;
                ld.IsWidthDecreasing = false;
                ld.JitterDecayRate = 0.5f;
                ld.SubdivisionFraction = new Range(0.45f, 0.55f);
                ld.Topology.Add(LightningSubdivisionOp.Jitter);
                ld.Topology.Add(LightningSubdivisionOp.Jitter);
                ld.Topology.Add(LightningSubdivisionOp.Jitter);
                ld.Topology.Add(LightningSubdivisionOp.Jitter);
                ld.Topology.Add(LightningSubdivisionOp.Jitter);
                ld.Topology.Add(LightningSubdivisionOp.Jitter);
                return ld;
            }
        }

        public static LightningDescriptor ExamplePreset
        {
            get
            {
                LightningDescriptor ld = new LightningDescriptor();
                ld.BaseWidth = 0.3f;
                ld.ExteriorColor = Color.Red;
                ld.ForkDecayRate = 0.7f;
                ld.ForkForwardDeviation = new Range(-1, 1);
                ld.ForkLeftDeviation = new Range(-1, 1);
                ld.ForkLengthPercentage = 0.2f;
                ld.InteriorColor = Color.Green;
                ld.IsWidthDecreasing = false;
                ld.JitterDeviationRadius = 0.4f;
                ld.JitterDecayRate = 1.0f;
                ld.SubdivisionFraction = new Range(0.2f, 0.8f);
                ld.AnimationFramerate = 20.0f;
                ld.Topology.Add(LightningSubdivisionOp.Jitter);
                ld.Topology.Add(LightningSubdivisionOp.Jitter);
                ld.Topology.Add(LightningSubdivisionOp.Jitter);
                ld.Topology.Add(LightningSubdivisionOp.Jitter);
                ld.Topology.Add(LightningSubdivisionOp.JitterAndFork);
                ld.Topology.Add(LightningSubdivisionOp.Jitter);
                ld.Topology.Add(LightningSubdivisionOp.Jitter);

                return ld;
            }
        }

        [XmlElement("Topology")]
        public SerializableList<LightningSubdivisionOp> Topology
        {
            get { return topology; }
            set { topology = value; }
        }

        [XmlElement("AnimationFramerate")]
        public float AnimationFramerate
        {
            get { return animationFramerate; }
            set { animationFramerate = value; }
        }

        [XmlElement("IsWidthDecreasing")]
        public bool IsWidthDecreasing
        {
            get { return isWidthDecreasing; }
            set { isWidthDecreasing = value; }
        }

        [XmlElement("BaseWidth")]
        public float BaseWidth
        {
            get { return baseWidth; }
            set { baseWidth = value; }
        }

        [XmlElement("ExteriorColor")]
        public Color ExteriorColor
        {
            get { return exteriorColor; }
            set { exteriorColor = value; }
        }

        [XmlElement("InteriorColor")]
        public Color InteriorColor
        {
            get { return interiorColor; }
            set { interiorColor = value; }
        }

        [XmlElement("SubdivisionFraction")]
        public Range SubdivisionFraction
        {
            get { return subdivisionFraction; }
            set { subdivisionFraction = value; }
        }

        [XmlElement("JitterForwardDeviation")]
        public Range JitterForwardDeviation
        {
            get { return jitterForwardDeviation; }
            set { jitterForwardDeviation = value; }
        }

        [XmlElement("JitterLeftDeviation")]
        public Range JitterLeftDeviation
	    {
		    get { return jitterLeftDeviation;}
		    set { jitterLeftDeviation = value;}
	    }

        [XmlElement("JitterDeviationRadius")]
        public float JitterDeviationRadius
        {
            get { return jitterDeviationRadius; }
            set { jitterDeviationRadius = value; }
        }

        [XmlElement("JitterDecayRate")]
        public float JitterDecayRate
        {
            get { return jitterDecayRate; }
            set { jitterDecayRate = value; }
        }

        [XmlElement("ForkLengthPercentage")]
        public float ForkLengthPercentage
        {
            get { return forkLengthPercentage; }
            set { forkLengthPercentage = value; }
        }

        [XmlElement("ForkDecayRate")]
        public float ForkDecayRate
        {
            get { return forkDecayRate; }
            set { forkDecayRate = value; }
        }

        [XmlElement("ForkForwardDeviation")]
        public Range ForkForwardDeviation
        {
            get { return forkForwardDeviation; }
            set { forkForwardDeviation = value; }
        }

        [XmlElement("ForkLeftDeviation")]
        public Range ForkLeftDeviation
        {
            get { return forkLeftDeviation; }
            set { forkLeftDeviation = value; }
        }

        #region Serialization
        public void Serialize(string file)
        {
            using (FileStream fs = new FileStream(file, FileMode.Create, FileAccess.Write))
            {
                XmlSerializer x = new XmlSerializer(typeof(LightningDescriptor));
                x.Serialize(fs, this);
            }
        }

        public static LightningDescriptor Deserialize(string file)
        {
            using (FileStream fs = new FileStream(file, FileMode.Open, FileAccess.Read))
            {
                XmlSerializer x = new XmlSerializer(typeof(LightningDescriptor));
                return (LightningDescriptor)x.Deserialize(fs);
            }
        }
        #endregion

        #region IDisposable Members

        public void Dispose()
        {
        }

        #endregion
    }
}
